home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / MacApp Release 10 / MacApp Release 10 - HD Ready / Libraries / ODMemMgr / Sources / MemDebg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-03  |  16.9 KB  |  656 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MemDebg.cpp
  3.  
  4.     Contains:    Memory management debug routine implementations
  5.  
  6.     Owned by:    Jens Alfke
  7.     Owned by:    Jens Alfke, Vincent Lo, Nick Pilch, Michael Burbidge
  8.  
  9.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.                   3/5/96    TWB        Comment out unused arguments to suppress warnings. 
  13.         <25>      3/4/96    TWB        Add MMPrintf wrapper around somPrintf. 
  14.         <24>     2/13/96    srf        Build variation for MacApp
  15.         <23>     10/3/95    TJ        Opps, I had left some code in that had been
  16.                                     if defed out.
  17.         <22>     10/3/95    TJ        Changes done by RefBall Team
  18.         <21>      8/8/95    TJ        Declared FindLeaksProc extern C
  19.         <20>      8/7/95    TJ        Typecast &InitLeaksProc to
  20.                                     (MMBlockInfoProc) for the MMWalkHeap call
  21.                                     so it will compile with SCpp.
  22.         <19>      8/4/95    DM        Leak checking [1267956]
  23.         <18>     6/21/95    JBS        turn off heap validation for ∂SOM data xfer
  24.         <17>      6/7/95    jpa        Changed old (pre-SLIM) SOM includes to
  25.                                     som.xh [1256901]
  26.         <16>      5/4/95    jpa        Added MMFindBlockContaining [1246077]
  27.         <15>    12/20/94    jpa        Add stub routines in non-debug config so
  28.                                     library will build. [1188344]
  29.         <14>     12/5/94    jpa        Nuked errant pragma lib_export's. [1195676]
  30.         <13>    10/24/94    jpa        Constness [1194286]
  31.         <12>     9/29/94    RA        1189812: Mods for 68K build.
  32.         <11>     9/20/94    VL        jpa: Fixed infinite recursion in heap
  33.                                     validation.
  34.         <10>     9/14/94    jpa        Eliminated dependencies on rest of OpenDoc.
  35.                                     OD-->MM. [1186692]
  36.          <9>      9/9/94    jpa        Made ODValidatePtr more robust.
  37.          <8>     8/19/94    NP        1181622: Ownership fix.
  38.          <7>     8/17/94    jpa        Added ODWalkHeap, greatly improved
  39.                                     ODValidateObject, and added debugging
  40.                                     checks using the SOM-block flag. [1179567]
  41.          <6>      8/8/94    jpa        Added ODGetHeapInfo. [1179567]
  42.          <5>      8/2/94    jpa        Plenty more fixes to validation.
  43.          <4>     7/26/94    jpa        Got validation stuff to work again.
  44.          <3>     6/18/94    MB        Include MemDebgP.h
  45.          <2>     6/10/94    MB        Make it build
  46.          <1>      6/9/94    MB        first checked in
  47.          <3>     5/27/94    jpa        New exception support [1165267]
  48.          <2>     5/27/94    MB        #1162181: Fixed MMM integration bug
  49.          <1>     5/27/94    MB        first checked in
  50.     To Do:
  51.     
  52.     In Progress:
  53.         
  54. */
  55.  
  56. #ifndef _MEMCNFIG_
  57. #include "MemCnfig.h"
  58. #endif
  59.  
  60. #ifndef _MEMDEBG_
  61. #include "MemDebg.h"
  62. #endif
  63.  
  64.  
  65. #if MM_DEBUG
  66.  
  67.  
  68. #ifndef _MEMMGRPV_
  69. #include "MemMgrPv.h"
  70. #endif
  71.  
  72. #ifndef _MEMHOOKS_
  73. #include "MemHooks.h"
  74. #endif
  75.  
  76. #include <string.h>
  77.  
  78. #if !defined(qMacApp)
  79. #ifndef __SOM__
  80. #include <som.xh>
  81. #endif
  82.  
  83. #include <SOMObj.xh>
  84. #endif
  85.  
  86. #ifndef _CRAWL_
  87. #include "Crawl.h"
  88. #endif
  89.  
  90. #ifndef __LOWMEM__
  91. #include <LowMem.h>
  92. #endif
  93.  
  94.  
  95. //==============================================================================
  96. // Global variable definitions
  97. //==============================================================================
  98.  
  99. MMBoolean gValidate = 0;
  100. MMBoolean gHeapChecking = 0;
  101.  
  102.  
  103. //==============================================================================
  104. // Function definitions
  105. //==============================================================================
  106. #if defined(qMacApp)
  107. MMBoolean
  108. MMFindBlockContaining( const void *start, const void *end,
  109.                        const void* *blockStart, const void* *blockEnd );
  110.  
  111. MMBoolean
  112. MMValidateMemoryRange( const void *start, const void *end );
  113.  
  114. MMBoolean
  115. MMTrackStackCrawls( MMBoolean track );
  116.  
  117. StackCrawl*
  118. MMGetBlockStackCrawl( const void *block, long *flags );
  119.  
  120. void
  121. MMSetBlockStackCrawl( const void *block, StackCrawl *s, long flags );
  122.  
  123. void
  124. MMEndLeakChecking( );
  125.  
  126. void
  127. MMBeginLeakChecking( );
  128. #endif
  129.  
  130. //------------------------------------------------------------------------------
  131. // DoesHeapExist
  132. //------------------------------------------------------------------------------
  133.  
  134. MMBoolean MMDoesHeapExist( MemHeap *heap )
  135. {
  136.     if( ((MemoryHeap*)heap)->GetLocation()==kMMSysMemory )
  137.         return kMMTrue;        // A system heap might have been allocated by another process.
  138.         
  139.     for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() )
  140.         if( h == (MemoryHeap*)heap )
  141.             return kMMTrue;
  142.     return kMMFalse;
  143. }
  144.  
  145. //------------------------------------------------------------------------------
  146. // MMBeginMemValidation
  147. //------------------------------------------------------------------------------
  148.  
  149. void
  150. MMBeginMemValidation( )
  151. {
  152.     MMValidateAllHeaps();
  153.     if( gValidate==0 )
  154.         for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() ) {
  155.             h->SetZapOnAllocate(kMMTrue);
  156.             h->SetZapOnFree(kMMTrue);
  157.             h->SetAutoValidation(kMMTrue);
  158.         }
  159.     gValidate++;
  160. }
  161.  
  162. //------------------------------------------------------------------------------
  163. // MMEndMemValidation
  164. //------------------------------------------------------------------------------
  165.  
  166. void
  167. MMEndMemValidation( )
  168. {
  169.     if( gValidate<=0 ) {
  170.         MM_WARN("Improper nesting of memory-validation calls");
  171.         return;
  172.     }
  173.     
  174.     MMValidateAllHeaps();
  175.     gValidate--;
  176.     if (gValidate==0)
  177.         for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() ) {
  178.             h->SetZapOnAllocate(kMMFalse);
  179.             h->SetZapOnFree(kMMFalse);
  180.             h->SetAutoValidation(kMMFalse);
  181.         }
  182. }
  183.  
  184. //------------------------------------------------------------------------------
  185. // MMBeginHeapChecking
  186. //------------------------------------------------------------------------------
  187.  
  188. void
  189. MMBeginHeapChecking( )
  190. {
  191.     gHeapChecking++;
  192.     MMBeginMemValidation();
  193. }
  194.  
  195. //------------------------------------------------------------------------------
  196. // MMEndHeapChecking
  197. //------------------------------------------------------------------------------
  198.  
  199. void
  200. MMEndHeapChecking( )
  201. {
  202.     if( gHeapChecking<=0 ) {
  203.         MM_WARN("Improper nesting of heap-checking calls");
  204.         return;
  205.     }
  206.     
  207.     gHeapChecking--;
  208.     MMEndMemValidation();
  209. }
  210.  
  211. //------------------------------------------------------------------------------
  212. // MMValidateHeap
  213. //------------------------------------------------------------------------------
  214.  
  215. static Boolean
  216. HeapCheckProc( const void *blk, unsigned long /*size*/, Boolean isObject, void *refCon )
  217. {
  218.     if( isObject ) {
  219.         (*(MMULong*)refCon) ++;                            // Increment object count
  220.         MMValidateObject((SOMObject*)blk);
  221.     }
  222.     return true;
  223. }
  224.  
  225.  
  226. MMBoolean
  227. MMValidateHeap( MemHeap *heapID, const void* /*ptr*/ )
  228. {
  229.     if (!heapID )
  230.         heapID = MMGetDefaultHeap();
  231.  
  232.     MM_ASSERT(heapID);
  233.     
  234. #if 0
  235.     if (!MMDoesHeapExist(heapID)) {
  236.         if( ptr )
  237.             MM_WARN("%p's heap at %p is unknown", ptr,heapID);
  238.         else
  239.             MM_WARN("%p is not a known heap", heapID);
  240.         return kMMFalse;
  241.     }
  242. #endif
  243.  
  244.     MMULong objects = 0;
  245.     ((MemoryHeap*)heapID)->Check(&HeapCheckProc,&objects);
  246.     
  247.     return kMMTrue;
  248. }
  249.  
  250.  
  251. //------------------------------------------------------------------------------
  252. // MMValidateAllHeaps
  253. //------------------------------------------------------------------------------
  254.  
  255. MMBoolean
  256. MMValidateAllHeaps( )
  257. {
  258.     MMBoolean result = kMMTrue;
  259.     for( MemoryHeap *h = MemoryHeap::GetFirstHeap(); h; h = h->GetNextHeap() )
  260.         if( !MMValidateHeap((MemHeap*)h) )
  261.             result = kMMFalse;
  262.     return result;
  263. }
  264.  
  265.  
  266. //------------------------------------------------------------------------------
  267. // MMValidatePtr
  268. //------------------------------------------------------------------------------
  269.  
  270. MMBoolean
  271. MMValidatePtr( const void* p, MMBoolean validateHeap, const char *operation )
  272. {
  273.     // If we could be sure that p were in the app zone, we could be more
  274.     // stringent. But it might be in the System heap or in temp-mem.
  275.     
  276.     const char *err = BasicValidatePtr(p);
  277.     if( !err ) {
  278.         BestFitHeap *heap = (BestFitHeap*) gDefaultHeap->GetBlockHeap(p);
  279.         
  280. #if 0
  281.         if (!MMDoesHeapExist((MemHeap*)heap))
  282.             if( operation )
  283.                 MM_WARN("%s(%p): block's heap %p is unknown", operation,p,heap);
  284.             else
  285.                 MM_WARN("%p's heap %p is unknown", p,heap);
  286. #endif
  287.         
  288.         if( !heap->IsValidBlock(p) ) {
  289.             err = "is invalid";
  290. #if !defined(qMacApp)
  291.             // SRF added gHaveSOM test before som call
  292.             if( gHaveSOM && somIsObj((void*)p) ) {
  293.                 MM_WARN("Invalid block %p is an object of class %s",
  294.                             p, ((SOMObject*)p)->somGetClassName() );
  295.             }
  296. #endif
  297.         } else if( validateHeap && !MMValidateHeap((MemHeap*)heap,p) )
  298.             return kMMFalse;    // ODValidateHeap already warns the user
  299.         else
  300.             return kMMTrue;
  301.     }
  302.     
  303.     if( operation )
  304.         MM_WARN("%s(%p): ptr %s!",operation,p,err);
  305.     else
  306.         MM_WARN("Pointer %p %s!",p,err);
  307.     return kMMFalse;
  308. }
  309.  
  310.  
  311. //------------------------------------------------------------------------------
  312. // MMValidateObject
  313. //------------------------------------------------------------------------------
  314.  
  315. static MMBoolean
  316. BasicIsObject( const void *block )
  317. {
  318.     // This is like MMIsObject but does not do any heap checking, which would
  319.     // be fatal if MMValidateObject were already being called during a heap-check!
  320.     
  321.     MemoryHeap *heap = gDefaultHeap->GetBlockHeap(block);
  322.     return heap ?heap->BlockIsObject(block) :kMMFalse;
  323. }
  324.  
  325. MMBoolean
  326. MMValidateObject( const SOMObject *o )
  327. {
  328.     // I mustn't check the heap, since I am called during heap checking!!
  329.     if( !MMValidatePtr(o,kMMFalse,"MMValidateObject") )
  330.         return kMMFalse;
  331.     
  332.     const char *err;
  333.     if( !BasicIsObject(o) )
  334.         err = "is not marked as an object in the heap";
  335. #if !defined(qMacApp)
  336.     else if( !gHaveSOM || !somIsObj((SOMObject*)o) )
  337.         err = "is not a SOM object";
  338. #endif
  339.     else
  340.         return kMMTrue;
  341.     
  342.     MM_WARN("Object %p %s!", o, err);
  343.     return kMMFalse;
  344. }
  345.  
  346. //------------------------------------------------------------------------------
  347. // MMGetHeapInfo
  348. //------------------------------------------------------------------------------
  349.  
  350. void
  351. MMGetHeapInfo( MemHeap *heapID,
  352.                 const char* *name, size_t *allocated, size_t *free,
  353.                 size_t *nBlocks, size_t *nObjects )
  354. {
  355.     MemoryHeap *heap = (MemoryHeap*)( heapID ?heapID :MMGetDefaultHeap() );
  356.     
  357.     if( name )        *name = heap->GetDescription();
  358.     if( allocated )    *allocated = heap->BytesAllocated();
  359.     if( free )        *free = heap->BytesFree();
  360.     if( nBlocks )    *nBlocks = heap->NumberAllocatedBlocks();
  361.     
  362.     if( nObjects ) {
  363.         *nObjects = 0;
  364.         heap->Check(&HeapCheckProc,&*nObjects);
  365.     }
  366. }
  367.  
  368.  
  369. //------------------------------------------------------------------------------
  370. // MMWalkHeap
  371. //------------------------------------------------------------------------------
  372.  
  373. struct HeapWalkData {
  374.     MMBlockInfoProc proc;
  375.     void *refCon;
  376. };
  377.  
  378. static Boolean CallHeapWalkProc( void *blk, unsigned long size, Boolean isObject,
  379.                                  void *refCon )
  380. {
  381.     if( isObject )
  382.         MMValidateObject((SOMObject*)blk);
  383.     else
  384.         MMValidatePtr(blk,false);
  385.         
  386.     HeapWalkData *data = (HeapWalkData*) refCon;
  387.     return (data->proc) (blk, size, isObject, data->refCon);
  388. }
  389.  
  390.  
  391.  
  392. void
  393. MMWalkHeap( MemHeap *heapID, MMBlockInfoProc proc, void *refCon )
  394. {
  395.     MemoryHeap *heap = (MemoryHeap*)( heapID ?heapID :MMGetDefaultHeap() );
  396.     
  397.     HeapWalkData data;
  398.     data.proc = proc;
  399.     data.refCon = refCon;
  400.     heap->Check((HeapWalkProc)CallHeapWalkProc,&data);
  401. }
  402.  
  403. MMBoolean
  404. MMFindBlockContaining( const void *start, const void *end,
  405.                        const void* *blockStart, const void* *blockEnd )
  406. {
  407.     const void *foo, *bar;
  408.     if( !blockStart ) blockStart=&foo;
  409.     if( !blockEnd   ) blockEnd=&bar;
  410.         
  411.     if( end<start ) {
  412.         const void *temp = end;
  413.         end = start;
  414.         start = temp;
  415.     }
  416.  
  417.     MemoryHeap *heap = (MemoryHeap*)MMGetDefaultHeap();
  418.     return heap->FindBlockContaining(start,end,*blockStart,*blockEnd);
  419. }
  420.  
  421.  
  422. MMBoolean
  423. MMValidateMemoryRange( const void *start, const void *end )
  424. {
  425.     // Warn if memory range is in default heap but not entirely within a valid block:
  426.     if( end<start ) {
  427.         const void *temp = end;
  428.         end = start;
  429.         start = temp;
  430.     }
  431.     const void *blockStart, *blockEnd;
  432.     MemoryHeap *heap = (MemoryHeap*)MMGetDefaultHeap();
  433.     if( heap->FindBlockContaining(start,end, blockStart,blockEnd) )
  434.         if( blockStart==NULL ) {
  435.             MM_WARN("Mem range %p--%p is in heap but not in any block", start,end);
  436.             return kMMFalse;
  437.         } else if( start<blockStart || end>blockEnd ) {
  438.             MM_WARN("Mem range %p--%p violates block %p--%p",
  439.                     start,end, blockStart,blockEnd);
  440.             return kMMFalse;
  441.         }
  442.     return kMMTrue;
  443. }
  444.  
  445.  
  446. //========================================================================================
  447. // Block Stack Crawls
  448. //========================================================================================
  449.  
  450. MMBoolean
  451. MMTrackStackCrawls( MMBoolean track )
  452. {
  453.     MMBoolean old = CBlockStackCrawlHook::gTrack;
  454.     CBlockStackCrawlHook::gTrack = track;
  455.     return old;
  456. }
  457.  
  458.  
  459. StackCrawl*
  460. MMGetBlockStackCrawl( const void *block, long *flags )
  461. {
  462.     BestFitHeap *heap = GetHeap(block,"MMGetBlockStackCrawl");
  463.     if( heap ) {
  464.         size_t s = (size_t) heap->GetBlockStackCrawl(block);
  465.         if( flags ) *flags = s & 3;
  466.         return (StackCrawl*)( s & ~3L );
  467.     } else {
  468.         if( flags ) *flags = 0;
  469.         return NULL;
  470.     }
  471. }
  472.  
  473.  
  474. void
  475. MMSetBlockStackCrawl( const void *block, StackCrawl *s, long flags )
  476. {
  477.     BestFitHeap *heap = GetHeap(block,"MMSetBlockStackCrawl");
  478.     if( heap )
  479.         heap->SetBlockStackCrawl( block, (StackCrawl*)( (size_t)s | (flags & 3)) );
  480. }
  481.  
  482.  
  483. //========================================================================================
  484. // Memory Leak Detection
  485. //========================================================================================
  486.  
  487.  
  488. struct LeakLink {
  489.     LeakLink*        fNext;
  490.     const void*        fFirstBlock;
  491.     StackCrawl*        fStack;
  492.     unsigned long    fCount;
  493. };
  494.  
  495. static LeakLink *sLeakLinks;
  496.  
  497.  
  498. static MMBoolean InitLeaksProc(  const void *blk, size_t /*size*/, MMBoolean /*isObject*/,
  499.                                     void */*refCon*/ )
  500. {
  501.     // Nuke all previous stack crawls:
  502.     long flags;
  503.     StackCrawl *s = MMGetBlockStackCrawl(blk,&flags);
  504.     if( s ) {
  505.         delete s;
  506.         MMSetBlockStackCrawl(blk,NULL,0);
  507.     }
  508.     return kMMTrue;
  509. }
  510.  
  511.  
  512. void
  513. MMBeginLeakChecking( )
  514. {
  515.     MMPrintf("••• Scanning for memory leaks: please do something 3 or more times.\r");
  516.     MMWalkHeap(NULL,(MMBlockInfoProc) &InitLeaksProc,NULL);
  517.     MMTrackStackCrawls(kMMTrue);
  518. }
  519.  
  520.  
  521. extern "C" {
  522. static MMBoolean FindLeaksProc(  const void *blk, size_t /*size*/, MMBoolean /*isObject*/,
  523.                                     void */*refCon*/ )
  524. {
  525.     long flags;
  526.     StackCrawl *s = MMGetBlockStackCrawl(blk,&flags);
  527.     if( s ) {
  528.         // This is a new block, check its stack crawl:
  529.         LeakLink *l;
  530.         for( l=sLeakLinks; l; l=l->fNext )
  531.             if( *(l->fStack) == *s ) {
  532.                 l->fCount++;
  533.                 delete s;
  534.                 MMSetBlockStackCrawl(blk,NULL,0);
  535.                 return kMMTrue;
  536.             }
  537.         l = new LeakLink;
  538.         l->fNext = sLeakLinks;
  539.         l->fFirstBlock = blk;
  540.         l->fStack = s;
  541.         l->fCount = 1;
  542.         sLeakLinks = l;
  543.     }
  544.     return kMMTrue;
  545. }
  546. }
  547.  
  548. static MMBoolean DumpObjProc(  const void *blk, size_t size, MMBoolean isObject,
  549.                                 void *dumpStack )
  550. {
  551.     if( isObject ) {
  552.         MMValidateObject((SOMObject*)blk);
  553.  
  554. #if !defined(qMacApp)
  555.         MMPrintf("  %p %4lu  %s\r", blk,size, ((SOMObject*)blk)->somGetClassName());
  556. #endif
  557.     } else if( dumpStack )
  558.         MMPrintf("  %p %4lu\r", blk,size);
  559.     if( dumpStack ) {
  560.         StackCrawl *s = MMGetBlockStackCrawl(blk,NULL);
  561.         if( s ) {
  562.             for( long i=0; i<s->CountFrames(); i++ ) {
  563.                 char name[256];
  564.                 s->GetFrameName(i,name);
  565.                 MMPrintf("        %s\n",name);
  566.             }
  567.         }
  568.     }
  569.     return true;        // Might check for cmd-period or something to abort...
  570. }
  571.  
  572. void
  573. MMEndLeakChecking( )
  574. {
  575.     MMTrackStackCrawls(kMMFalse);
  576.     
  577.     MMPrintf("••• Dumping memory leaks:\r");
  578.     sLeakLinks = NULL;
  579.     MMWalkHeap(NULL,&FindLeaksProc,NULL);
  580.     size_t leakage = 0;
  581.     LeakLink *next;
  582.     for( LeakLink *l=sLeakLinks; l; l=next ) {
  583.         next = l->fNext;
  584.         if( l->fCount >= 3 ) {
  585.             MMPrintf("• Leaked %d times:\r", l->fCount);
  586.             size_t size = MMBlockSize(l->fFirstBlock);
  587.             DumpObjProc(l->fFirstBlock,
  588.                         size,
  589.                         MMIsObject(l->fFirstBlock),
  590.                         (void*)kMMTrue);
  591.             leakage += l->fCount * (size+8);    // Add 8 bytes for per-block overhead
  592.         }
  593.         delete l->fStack;
  594.         MMSetBlockStackCrawl(l->fFirstBlock,NULL,0);
  595.         delete l;
  596.     }
  597.     sLeakLinks = NULL;
  598.     if( leakage > 0 )
  599.         MMPrintf("••• Estimated leakage: %ld bytes\r", leakage);
  600.     else
  601.         MMPrintf("••• No leaks found!\r");
  602. }
  603.  
  604.  
  605. //========================================================================================
  606. // Non-Debug Stubs
  607. //========================================================================================
  608.  
  609. #else /* MM_DEBUG */
  610.  
  611.  
  612. void        MMBeginMemValidation( ) { }
  613. void        MMEndMemValidation( ) { }
  614. void        MMBeginHeapChecking( ) { }
  615. void        MMEndHeapChecking( ) { }
  616.  
  617. MMBoolean    MMValidatePtr( ConstMMBlock, MMBoolean /*validateHeap*/, const char */*operation*/ )    {return 1;}
  618. MMBoolean    MMValidateObject( const SOMObject */*o*/ ) {return 1;}
  619. MMBoolean    MMValidateHandle( MMHandle ) {return 1;}
  620.  
  621. MMBoolean    MMDoesHeapExist( MemHeap */*heap*/ ) {return 1;}
  622. MMBoolean    MMValidateHeap( MemHeap */*heapID*/, const void* /*ptr*/ ) {return 1;}
  623. MMBoolean    MMValidateAllHeaps( ) {return 1;}
  624.  
  625. void        MMGetHeapInfo( MemHeap */*heapID*/,
  626.                             const char* */*name*/, size_t */*allocated*/, size_t */*free*/,
  627.                             size_t */*nBlocks*/, size_t */*nObjects*/ ) { }
  628.  
  629. void        MMWalkHeap( MemHeap */*heapID*/, MMBlockInfoProc, void */*StackCrawl*/ )  { }
  630.  
  631. MMBoolean    MMFindBlockContaining( const void *, const void*,
  632.                                     const void* *blockStart, const void* */*blockEnd*/ )
  633. {
  634.     if( blockStart ) *blockStart=NULL;
  635.     return 0;
  636. }
  637. MMBoolean    MMValidateMemoryRange( const void */*start*/, const void */*end*/ )    {return 1;}
  638.  
  639. MMBoolean    MMTrackStackCrawls( MMBoolean ) {return 0;}
  640.  
  641. #if defined(qMacApp)
  642. // Need a definition to be able to take a pointer
  643. class StackCrawl;    // external
  644. #endif
  645.  
  646. StackCrawl* MMGetBlockStackCrawl( const void */*block*/, long *flags )
  647.     {if( flags ) *flags = 0; return NULL;}
  648. void MMSetBlockStackCrawl( const void */*block*/, StackCrawl*, long /*flags*/ ) { }
  649.  
  650. void        MMBeginLeakChecking( void )    { }
  651. void        MMEndLeakChecking( void ) { }
  652.  
  653.  
  654.  
  655. #endif /*MMDebug*/
  656.